package com.apestech.framework.xml.plugin;

import com.apestech.formwork.xml.XmlQuery;
import com.apestech.framework.db.SqlSession;
import com.apestech.framework.json.JSONArray;
import com.apestech.framework.json.JSONObject;
import com.apestech.framework.sql.condition.ConditionMap;
import com.apestech.framework.sql.modul.FromList;
import com.apestech.framework.sql.modul.SqlList;
import com.apestech.framework.xml.condition.modul.*;
import com.apestech.framework.xml.condition.node.NodeAccount;
import com.apestech.framework.xml.condition.node.NodeCondition;
import com.apestech.framework.xml.condition.node.NodeConditionStrategy;
import com.apestech.framework.xml.condition.node.NodeReport;
import com.apestech.framework.xml.plugin.modul.*;
import com.apestech.framework.xml.plugin.node.NodeModel;
import com.apestech.framework.xml.plugin.node.NodeSpecialField;
import com.apestech.framework.xml.plugin.node.NodeSysCondition;
import com.apestech.framework.xml.pub.core.ElementUtil;
import com.apestech.framework.xml.pub.core.NodeJson;
import com.apestech.framework.xml.pub.core.XmlFile;
import com.apestech.framework.xml.plugin.node.NodeDatabase;
import com.apestech.framework.xml.sql.SqlNodeVar;
import com.apestech.framework.xml.sql.XmlSqlPaste;
import com.apestech.framework.xml.sql.modul.QueryRule;
import com.apestech.framework.xml.sql.modul.QueryhTw;
import com.apestech.framework.xml.sql.modul.SqlRule;
import com.apestech.framework.xml.sql.node.NodeHead;
import com.apestech.framework.xml.sql.node.NodeRule;
import com.apestech.framework.xml.sql.node.NodeSqlRule;
import com.apestech.framework.xml.sql.node.NodehTw;
import com.apestech.framework.xml.table.modul.Tables;
import com.apestech.framework.xml.table.node.NodeTables;
import org.dom4j.Element;

import java.util.List;

/**
 * @author hup
 * @create 2018-12-11-17:04
 */
public class XmlPaste extends ElementUtil {
    private Element node;
    private JSONObject result=new JSONObject();
    private JSONObject singleResult=new JSONObject();

    private XmlQuery xmlQuery;
    private Element root;
    private JSONArray auths;
    private boolean isSqlNode=false;

    private QueryhTw htw;
    private GridHead head;
    private QueryRule rule;
    private XmlSqlPaste xmlsql;
    private Database database;
    private QryConfig qryConfig;
    private FromList fromtab;
    private String sql;
    private SqlList param;
    private String autoCompletion;
    private String DBCN;
    private SqlRule sqlrule;

    private Tables table;
    private Condition condition;
    private Dimension dimension;
    private Model model;
    private SysCondition sysCondition;
    private SpecialField specialField;

    private ConditionStrategy conditionStrategy;
    private Account account;
    private Report report;

    public XmlPaste() throws Exception {
        xmlQuery=new XmlQuery();
    }

    public XmlPaste(SqlSession session) throws Exception {
        xmlQuery=new XmlQuery();
        xmlQuery.setSession(session);
    }

    public XmlPaste(String id, String type) throws Exception {
        xmlQuery=new XmlQuery(id);
        xmlQuery.setNodename(type);
        node=xmlQuery.getNode(id, type);
        root=xmlQuery.getRoot();
    }

    public XmlPaste(String id, String type, SqlSession session) throws Exception {
        xmlQuery=new XmlQuery(id);
        xmlQuery.setNodename(type);
        xmlQuery.setSession(session);
        node=xmlQuery.getNode(id, type);
        root=xmlQuery.getRoot();
    }

    public XmlPaste(String id, SqlSession session) throws Exception {
        xmlQuery=new XmlQuery(id);
        xmlQuery.setSession(session);
        node=xmlQuery.getNode(id);
        root=xmlQuery.getRoot();
    }

    public XmlPaste(String id, XmlQuery xmlQuery) throws Exception {
        this.xmlQuery=xmlQuery;
        node=this.xmlQuery.getNode(id);
        root=this.xmlQuery.getRoot();
    }

    public XmlPaste(String id, String str, XmlIdVar.STR_TYPE str_type) throws Exception {
        this.xmlQuery=new XmlQuery(str, str_type);
        node=this.xmlQuery.getNode(null,id);
        root=this.xmlQuery.getRoot();
    }

    public XmlPaste(String id, String type, XmlQuery xmlQuery) throws Exception {
        this.xmlQuery=xmlQuery;
        this.xmlQuery.setNodename(type);
        node=this.xmlQuery.getNode(id);
        root=this.xmlQuery.getRoot();
        setSession(xmlQuery.getSession());
    }

    public XmlPaste(String xmlString) throws Exception {
        root=getElementFromString(xmlString);
    }

    public void setNode(String xpath) throws Exception {
        if(this.root.selectSingleNode(xpath)==null) throw new Exception("传入结点ID ["+xpath+"]有误!");
        this.node= (Element) this.root.selectSingleNode(xpath);
        result=new JSONObject();
    }

    private Element getElementFromString(String xmlString) throws Exception {
        if(xmlString==null){
            throw new Exception("请检查下代码：传入参数为XML文件名或对应String！");
        }
        XmlFile file=new XmlFile();
        if(xmlString.indexOf("<")>=0){
            file.loadFromString(xmlString, false);
        }
        else file.loadFromFile(xmlString);
        Element root=file.getRoot();
        return root;
    }

    public void expainSql(String xmlstr, SqlNodeVar.SqlType type, String fromtab) throws Exception {
        xmlsql=new XmlSqlPaste(xmlstr, type, xmlQuery.getSession());
    }

    public void expain(Element root, Element node) throws Exception {
        this.root=root;
        this.node=node;
        xmlQuery.setRNode(root, node);
        expain();
    }

    public void expain() throws Exception {
         if(node==null) return;
         boolean flag=isSqlNode;
         if(flag){
             if(node!=null){
                 if(node.selectSingleNode("sql")==null) xmlsql=new XmlSqlPaste(root, node, xmlQuery.getSession());
                 else flag=false;
            }
        }
         if(!flag) {
            if(!getNode(node)){
                List<?> list=node.content();
                int len=list.size();
                for(int i=0; i<len; i++){
                    String scalss=list.get(i).getClass().getName();
                    if(scalss.equals("org.dom4j.tree.DefaultElement")){
                        getNode((Element) list.get(i));
                    }
                }
            }
        }
    }

    private boolean getNode(Element eml) throws Exception {
        boolean flag=false;
        String name=eml.getName();
        switch(name){
            case "database":{
                if(database==null){
                    NodeDatabase db=new NodeDatabase(eml);
                    db.getAllDb();
                    database=db.getDb();
                    flag=true;
                }
                break;
            }
            case "specialField":{
                if(specialField==null){
                    NodeSpecialField nodeSpecialField=new NodeSpecialField(eml);
                    nodeSpecialField.getAllField();
                    specialField=nodeSpecialField.getSpecialField();
                    flag=true;
                }
                break;
            }
            case "model":{
                if(model==null){
                    NodeModel nmodel=new NodeModel(eml);
                    nmodel.getAllModel();
                    model=nmodel.getModel();
                    flag=true;
                }
                break;
            }
            case "sysCondition":{
                if(sysCondition==null){
                    NodeSysCondition nodeSysCondition=new NodeSysCondition(xmlQuery.getSession(), node);
                    nodeSysCondition.getCondition();
                    sysCondition=nodeSysCondition.getSysCondition();
                    flag=true;
                }
                break;
            }
            case "hTw": {
                //if(htw==null){
                    NodehTw nhtw=new NodehTw(eml);
                    nhtw.getAllHtw();
                    htw=nhtw.getHtw();
                //}
                break;
            }
            case "head": {
                //if(head==null){
                    NodeHead nhead=new NodeHead(eml);
                    nhead.expain();
                    head=nhead.getHead();
                //}
                break;
            }
            case "rule": {
                //if(rule==null){
                    NodeRule nrule=new NodeRule(eml);
                    nrule.getAllRule();
                    rule=nrule.getRule();
                //}
                break;
            }
            case "select": {
                setXmlPaste(eml, "select");
                break;
            }
            case "queryid": {
                setXmlPaste(eml, "select");
                break;
            }
            case "table":{
                setXmlPaste(eml, "table");
                break;
            }
            case "auth": {
                JSONObject attr = getNodeAttr(eml);
                if (attr != null) {
                    if (auths == null) auths = new JSONArray();
                    auths.add(attr.get("attrNode"));
                }
                break;
            }
            case "qryConfig": {
                //if(qryConfig==null){
                    JSONObject attr = getNodeAttr(eml);
                    if (attr != null) {
                        qryConfig=new QryConfig((JSONObject) attr.get("attrNode"));
                    }
                //}
                break;
            }
            case "tables":{
                //if(table==null){
                    NodeTables create=new NodeTables(eml, xmlQuery);
                    create.getAllDb();
                    table=create.getTable();
                    table.expain(xmlQuery.getSession());
                    flag=true;
                //}
                break;
            }
            case "sqlrule":{
                //if(sqlrule==null){
                    NodeSqlRule nodeSqlRule=new NodeSqlRule(eml);
                    nodeSqlRule.expain();
                    sqlrule=nodeSqlRule.getSqlrule();
                //}
                break;
            }
            case "conditionDef": {
                //if(condition==null){
                    NodeCondition nodeCondition=new NodeCondition(eml, xmlQuery);
                    nodeCondition.getData();
                    condition=nodeCondition.getCondition();
                //}
                break;
            }
            case "dimensionDef": {
                //if(dimension==null){
                    dimension=new Dimension(xmlQuery.getSession());
                    NodeJson json=new NodeJson(eml);
                    json.expain();
                    JSONObject m=json.getResult();
                    dimension.setDimension(m);
                    JSONArray list= null;
                    if(m.get("field") instanceof JSONObject ){
                        list=new JSONArray();
                        list.add(m.get("field"));
                    } else list=(JSONArray) m.get("field");
                    int len=list.size();
                    for(int i=0; i<len; i++){
                        dimension.addField(list.get(i));
                    }
                //}
                break;
            }
            case "conditionStrategyDef":{
                //if(conditionStrategy==null){
                    NodeConditionStrategy nodeConditionStrategy=new NodeConditionStrategy(eml);
                    nodeConditionStrategy.getData();
                    conditionStrategy=nodeConditionStrategy.getConditionStrategy();
                //}
                break;
            }
            case "accountDef":{
                //if(account==null){
                    NodeAccount nodeAccount=new NodeAccount(eml, xmlQuery.getSession());
                    nodeAccount.getData();
                    account=nodeAccount.getAccount();
                //}
                break;
            }
            case "report":{
                //if(report==null){
                    NodeReport nodeReport=new NodeReport(xmlQuery, eml);
                    nodeReport.getData();
                    report=nodeReport.getReport();
                //}
                break;
            }
            default:{
                NodeJson json=new NodeJson(eml);
                json.expain();
                singleResult=json.getResult();
                result.putAll(singleResult);
                flag=true;
            }
        }
        return flag;
    }

    private void setXmlPaste(Element eml, String name) throws Exception {
//        if(xmlQuery.getSession()==null) throw new Exception("检查代码，session不能为空！");
        String key=eml.attributeValue("id");
        String type=eml.attributeValue("type");
        XmlSqlPaste x=new XmlSqlPaste(root, getNode(key, eml, name), xmlQuery.getSession());
        if(xmlsql==null) xmlsql=x;
        else xmlsql.setXmlSqlPaste(x);
        if(type!=null) x.setSqlType(type);
    }

    private Element getNode(String key, Element eml, String name) throws Exception {
        Element ele=null;
        if(key.indexOf(".")>=0){
            if(xmlQuery.getSession()!=null) xmlQuery.setTheme(xmlQuery.getSession().getTheme());
            ele=xmlQuery.getNode(key);
        } else ele=getNode(root, eml, name, key);
        return ele;
    }

    public JSONObject getResult() {
        return result;
    }

    public JSONObject getSingleResult() {
        return singleResult;
    }

    public QueryhTw getHtw() {
        if(htw!=null) return htw;
        if(xmlsql!=null && xmlsql.getHtw()!=null) return xmlsql.getHtw();
        if(xmlsql!=null && xmlsql.getXmlSqlPaste()!=null && xmlsql.getXmlSqlPaste().getHtw()!=null) return xmlsql.getXmlSqlPaste().getHtw();
        return null;
    }

    public GridHead getHead() {
        if(head!=null && head.getHeadjson()!=null && head.getHeadjson().size()>0) return head;
        if(xmlsql!=null && xmlsql.getHead()!=null && xmlsql.getHead().getHeadjson()!=null
                && xmlsql.getHead().getHeadjson().size()>0) return xmlsql.getHead();
        if(xmlsql!=null && xmlsql.getXmlSqlPaste()!=null && xmlsql.getXmlSqlPaste().getHead()!=null
                && xmlsql.getXmlSqlPaste().getHead().getHeadjson()!=null
                && xmlsql.getXmlSqlPaste().getHead().getHeadjson().size()>0) return xmlsql.getXmlSqlPaste().getHead();
        return null;
    }

    public QueryRule getRule() {
        if(rule!=null) return rule;
        if(xmlsql!=null && xmlsql.getRule()!=null) return xmlsql.getRule();
        if(xmlsql!=null && xmlsql.getXmlSqlPaste()!=null && xmlsql.getXmlSqlPaste().getRule()!=null) return xmlsql.getXmlSqlPaste().getRule();
        return null;
    }

    public void setSession(SqlSession session) throws Exception {
        if(xmlQuery==null) xmlQuery=new XmlQuery();
        xmlQuery.setSession(session);
    }

    public void setRoot(Element root) {
        this.root = root;
    }

    public JSONArray getAuths() {
        if(auths!=null) return auths;
        if(xmlsql!=null && xmlsql.getAuths()!=null) return xmlsql.getAuths();
        if(xmlsql!=null && xmlsql.getXmlSqlPaste()!=null && xmlsql.getXmlSqlPaste().getAuths()!=null) return xmlsql.getXmlSqlPaste().getAuths();
        return null;
    }

    public SqlRule getSqlrule() {
        if(sqlrule!=null) return sqlrule;
        if(xmlsql!=null && xmlsql.getSqlrule()!=null) return xmlsql.getSqlrule();
        if(xmlsql!=null && xmlsql.getXmlSqlPaste()!=null && xmlsql.getXmlSqlPaste().getSqlrule()!=null) return xmlsql.getXmlSqlPaste().getSqlrule();
        return null;
    }

    public String getSqlType() {
        if(xmlsql!=null && xmlsql.getSqlType()!=null){
            return xmlsql.getSqlType();
        }
        if(xmlsql!=null && xmlsql.getXmlSqlPaste()!=null && xmlsql.getXmlSqlPaste().getSqlType()!=null){
            return xmlsql.getXmlSqlPaste().getSqlType();
        }
        return null;
    }

    public JSONObject getOther(){
        if(xmlsql!=null && xmlsql.getOther()!=null){
            return xmlsql.getOther();
        }
        if(xmlsql!=null && xmlsql.getXmlSqlPaste()!=null && xmlsql.getXmlSqlPaste().getOther()!=null){
            return xmlsql.getXmlSqlPaste().getOther();
        }
        return null;
    }

    public void setSqlNode(boolean sqlNode) {
        isSqlNode = sqlNode;
    }

    public QryConfig getQryConfig() {
        return qryConfig;
    }

    public Database getDatabase() {
        return database;
    }

    public SpecialField getSpecialField() {
        return specialField;
    }

    public String getSql(){
        return sql;
    }

    public SqlList getParam() {
        return param;
    }

    public String getAutoCompletion() {
        return autoCompletion;
    }

    public String getDBCN() {
        return DBCN;
    }

    public String getExecSql(ConditionMap input) throws Exception{
        if(xmlsql==null) return "";
        sql=null;
        sql=xmlsql.getSql(input);
        param=xmlsql.getParam();
        autoCompletion=xmlsql.getAutoCompletion();
        DBCN=xmlsql.getDBCN();
        if((sql==null || "".equals(sql.trim())) && xmlsql.getXmlSqlPaste()!=null){
            sql=xmlsql.getXmlSqlPaste().getSql(input);
            param=xmlsql.getXmlSqlPaste().getParam();
            autoCompletion=xmlsql.getXmlSqlPaste().getAutoCompletion();
            DBCN=xmlsql.getXmlSqlPaste().getDBCN();
        }
        return sql;
    }

    public FromList getFromtab() throws Exception {
        if(fromtab!=null) return fromtab;
        if(xmlsql==null) return null;
        if(xmlsql.getXmlSqlPaste()!=null && xmlsql.getXmlSqlPaste().getFromtab()!=null){
            fromtab=xmlsql.getXmlSqlPaste().getFromtab();
            return fromtab;
        }
        if(xmlsql.getXmlSqlPaste()!=null && xmlsql.getXmlSqlPaste().getRule()!=null && xmlsql.getXmlSqlPaste().getRule().getFrom()!=null){
            fromtab=new FromList(xmlsql.getXmlSqlPaste().getRule().getFrom(), null, xmlQuery.getSession());
            return fromtab;
        }
        if(xmlsql!=null && xmlsql.getFromtab()!=null){
            fromtab=xmlsql.getFromtab();
            return fromtab;
        }
        if(xmlsql!=null && xmlsql.getRule()!=null && xmlsql.getRule().getFrom()!=null){
            fromtab=new FromList(xmlsql.getRule().getFrom(), null, xmlQuery.getSession());
            return fromtab;
        }
        return null;
    }

    public XmlSqlPaste getXmlsql() {
        return xmlsql;
    }

    public Tables getTable() {
        return table;
    }

    public Condition getCondition() {
        return condition;
    }

    public Element getNode() {
        return node;
    }

    public Dimension getDimension() {
        return dimension;
    }

    public Model getModel() {
        return model;
    }

    public SysCondition getSysCondition() {
        return sysCondition;
    }

    public ConditionStrategy getConditionStrategy() {
        return conditionStrategy;
    }

    public Account getAccount() {
        return account;
    }

    public Element getRoot() {
        return root;
    }

    public Report getReport() {
        return report;
    }

    public XmlQuery getXmlQuery() {
        return xmlQuery;
    }
}
